#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/cdev.h>
#include <linux/device.h>

#define DEVICE_NAME "simple_char_dev"  // 设备名
#define CLASS_NAME  "simple_char"     // 类名
#define BUFFER_SIZE 1024              // 缓冲区大小

static int major_number;            // 主设备号
static char device_buffer[BUFFER_SIZE];  // 缓冲区
static struct class*  char_class = NULL;  // 设备类
static struct device* char_device = NULL; // 设备
static struct cdev char_cdev;           // 字符设备结构体

// 打开设备时调用
static int device_open(struct inode *inode, struct file *file)
{
    printk(KERN_INFO "%s: Device opened\n", DEVICE_NAME);
    return 0;
}

// 释放设备时调用
static int device_release(struct inode *inode, struct file *file)
{
    printk(KERN_INFO "%s: Device released\n", DEVICE_NAME);
    return 0;
}

// 读设备时调用
static ssize_t device_read(struct file *file, char __user *buffer, size_t len, loff_t *offset)
{
    int bytes_read = 0;

    if (*offset >= BUFFER_SIZE)
        return 0;

    // 将缓冲区内容拷贝到用户空间
    while (len && *offset < BUFFER_SIZE) {
        put_user(device_buffer[*offset], buffer++);
        len--;
        (*offset)++;
        bytes_read++;
    }

    printk(KERN_INFO "%s: Read %d bytes\n", DEVICE_NAME, bytes_read);
    return bytes_read;
}

// 写设备时调用
static ssize_t device_write(struct file *file, const char __user *buffer, size_t len, loff_t *offset)
{
    int bytes_written = 0;

    if (*offset >= BUFFER_SIZE)
        return -ENOMEM;

    // 将用户空间数据拷贝到内核空间缓冲区
    while (len && *offset < BUFFER_SIZE) {
        get_user(device_buffer[*offset], buffer++);
        len--;
        (*offset)++;
        bytes_written++;
    }

    printk(KERN_INFO "%s: Written %d bytes\n", DEVICE_NAME, bytes_written);
    return bytes_written;
}

// 文件操作结构体
static struct file_operations fops = {
    .open = device_open,
    .release = device_release,
    .read = device_read,
    .write = device_write,
};

// 模块加载时调用
static int __init char_dev_init(void)
{
    // 动态分配主设备号
    major_number = register_chrdev(0, DEVICE_NAME, &fops);
    if (major_number < 0) {
        printk(KERN_ALERT "%s: Failed to register a major number\n", DEVICE_NAME);
        return major_number;
    }

    printk(KERN_INFO "%s: Registered with major number %d\n", DEVICE_NAME, major_number);

    // 创建设备类
    char_class = class_create(THIS_MODULE, CLASS_NAME);
    if (IS_ERR(char_class)) {
        unregister_chrdev(major_number, DEVICE_NAME);
        printk(KERN_ALERT "%s: Failed to register device class\n", DEVICE_NAME);
        return PTR_ERR(char_class);
    }

    // 创建设备
    char_device = device_create(char_class, NULL, MKDEV(major_number, 0), NULL, DEVICE_NAME);
    if (IS_ERR(char_device)) {
        class_destroy(char_class);
        unregister_chrdev(major_number, DEVICE_NAME);
        printk(KERN_ALERT "%s: Failed to create device\n", DEVICE_NAME);
        return PTR_ERR(char_device);
    }

    // 初始化字符设备
    cdev_init(&char_cdev, &fops);
    if (cdev_add(&char_cdev, MKDEV(major_number, 0), 1) == -1) {
        device_destroy(char_class, MKDEV(major_number, 0));
        class_destroy(char_class);
        unregister_chrdev(major_number, DEVICE_NAME);
        printk(KERN_ALERT "%s: Failed to add cdev\n", DEVICE_NAME);
        return -1;
    }

    printk(KERN_INFO "%s: Device successfully created\n", DEVICE_NAME);
    return 0;
}

// 模块卸载时调用
static void __exit char_dev_exit(void)
{
    cdev_del(&char_cdev);  // 删除字符设备
    device_destroy(char_class, MKDEV(major_number, 0));  // 删除设备
    class_destroy(char_class);  // 删除设备类
    unregister_chrdev(major_number, DEVICE_NAME);  // 注销设备
    printk(KERN_INFO "%s: Device successfully removed\n", DEVICE_NAME);
}

module_init(char_dev_init);
module_exit(char_dev_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("hrgxy");

